<?php
/* 冬至引擎种子文件
*
*
*/

namespace {

	/// 常量
	class Wse
	{
		/// 模拟JavaScript的Undefined
		public static $i_Udfn = null;

		/// 模拟JavaScript的Boolean类名
		public static $i_tBoolean = 'Boolean';

		/// 模拟JavaScript的Number类名
		public static $i_tNumber = 'Number';

		/// 模拟JavaScript的String类名
		public static $i_tString = 'String';

		/// 模拟JavaScript的Object类名
		public static $i_tObject = 'Object';

		/// 模拟JavaScript的Array类名
		public static $i_tArray = 'Array';
	}
}

namespace hpnWse {

/// 模拟JavaScript的Undefined
class tUdfn {}
\Wse::$i_Udfn = new tUdfn();

/// 是undfined？
function fIsUdfn($a_Any)
{
	return $a_Any === \Wse::$i_Udfn;
}

/// 是undfined或null？
function fIsUdfnOrNull($a_Any)
{
	return (null === $a_Any) || fIsUdfn($a_Any);
}

/// 是null或空串？
function fIsNullOrEstr($a_Any)
{
	return (null === $a_Any) || ('' === $a_Any);
}

/// 是undfined或null或空串？
function fIsUdfnOrNullOrEstr($a_Any)
{
	return ('' === $a_Any) || fIsUdfnOrNull($a_Any);
}

/// 是Boolean？
function fIsBool($a_Any)
{
	return is_bool($a_Any);
}

/// 是Number？
function fIsNum($a_Any)
{
	return is_int($a_Any) || is_double($a_Any);
}

/// 是String？
function fIsStr($a_Any)
{
	return is_string($a_Any);
}

//【不要提供这个函数，PHP和JS的数组在赋值时差异严重】
// /// 是否为Object？【注意】Array也是Object，但null和Function不是
// /// a_Any：任意
// /// 返回：Boolean，是否
// function fIsObj($a_Any)
// {
// 	return is_array($a_Any) || is_object($a_Any);
// }

/// 是数组或对象？
function fIsAryOrObj($a_Any)
{
	return is_array($a_Any) || is_object($a_Any);
}

/// 是纯对象（对应JavaScript的Object）？【注意】空数组认为是数组，若有“洞”则认为是纯对象
function fIsPureObj($a_Any, $a_Fast = false)
{
	return is_array($a_Any) && (! fIsAry($a_Any, $a_Fast));
}

/// 是数组（对应JavaScript的Array）？【注意】空数组认为是数组，若有“洞”则认为是纯对象
///【忽略，总是true】$a_Fast：Boolean，快速判断？true只会检查始末两个索引的存在性，默认false检查每个索引
function fIsAry($a_Any, $a_Fast = false)
{
	if (! is_array($a_Any)) { return false; }
	$l_Len = count($a_Any);
	return array_key_exists(0, $a_Any) && ((1 == $l_Len) || array_key_exists($l_Len - 1, $a_Any));
	// if ($a_Fast && ($l_Len > 1))
	// {
	// 	return array_key_exists(0, $a_Any) && array_key_exists($l_Len - 1, $a_Any);
	// }
	// else
	// {
	// 	for ($i=0; $i<$l_Len; ++$i)
	// 	{
	// 		if (! array_key_exists($i, $a_Any)) // 有“洞”
	// 		{ return false; }
	// 	}
	// 	return true;
	// }
}

/// 是纯对象或数组？
function fIsPureObjOrAry($a_Any)
{
	return is_array($a_Any);
}

/// 转成布尔，其中：
/// 字符串'0'和任意数组转成true；其余规则同内建函数empty：
/// "" (an empty string)
// 0 (0 as an integer)
// 0.0 (0 as a float)
// NULL
// FALSE
// array() (an empty array)
// $var; (a variable declared, but without a value)
function fBool($a_Any)
{
	return (('0' === $a_Any) || is_array($a_Any)) ? true : (!empty($a_Any));
}

/// 模拟JavaScript的“v1 || v2”
function fV1OrV2($a_V1, $a_V2)
{
	//【警告：'0'也被认为是false！】
	return fBool($a_V1) ? $a_V1 : $a_V2;
}

/// 获取主机IP
/// 返回：String，若是"::1"则转化为"127.0.0.1"
function fGetHostIp()
{
	$l_Rst = $_SERVER["SERVER_ADDR"];
	return ('::1' === $l_Rst) ? '127.0.0.1' : $l_Rst;
}

/// 获取客户端IP
/// 返回：String，若是"::1"则转化为"127.0.0.1"
function fGetClntIp()
{
	// 1 没有使用代理的情况
	//   REMOTE_ADDR = 客户端IP
	//   HTTP_X_FORWARDED_FOR = 没数值或不显示
	// 2 使用透明代理的情况
	//   REMOTE_ADDR = 最后一个代理服务器 IP
	//   HTTP_X_FORWARDED_FOR = 客户端真实 IP （经过多个代理服务器时，这个值类似：
	//	 221.5.252.160, 203.98.182.163, 203.129.72.215）
	//   这类代理服务器还是将客户端真实的IP发送给了访问对象,无法达到隐藏真实身份的目的.
	// 3 使用普通的匿名代理
	//   REMOTE_ADDR = 最后一个代理服务器 IP
	//   HTTP_X_FORWARDED_FOR = 代理服务器 IP （经过多个代理服务器时，这个值类似：
	//	 203.98.182.163, 203.98.182.163, 203.129.72.215）
	//   这种情况下隐藏了客户端的真实IP,但是向访问对象透露了客户端是使用代理服务器访问它们的.
	// 4 使用欺骗性代理服务器
	//   REMOTE_ADDR = 代理服务器 IP
	//   HTTP_X_FORWARDED_FOR = 随机的 IP（经过多个代理服务器时,这个值类似：
	//	 220.4.251.159, 203.98.182.163, 203.129.72.215）
	//   这种情况下同样透露了客户端是使用了代理服务器,但编造了一个虚假的随机IP（220.4.251.159）
	//   代替客户端的真实IP来欺骗它.
	// 5 使用高级匿名代理服务器
	//   REMOTE_ADDR = 代理服务器 IP
	//   HTTP_X_FORWARDED_FOR = 没数值或不显示，也可能是unknown

	// 先检查是否为本机
	$l_Rst = $_SERVER['REMOTE_ADDR'];
	if ('::1' == $l_Rst)
	{ return '127.0.0.1'; }

	// 然后代理？
	$l_FowdFor = $_SERVER['HTTP_X_FORWARDED_FOR'];
	if((! empty($l_FowdFor)) && (0 !== strcasecmp($l_FowdFor, 'unknown')))
	{
		$l_Rst = $l_FowdFor;

		// 处理多层代理的情况
	    // 或使用正则：preg_match('/[\d\.]{7,15}/', $l_Rst, $l_M) ? $l_M[0] : 'unknown';
	    if (false !== strpos($l_Rst, ','))
	    { $l_Rst = explode(',', $l_Rst); $l_Rst = $l_Rst[0]; }
	}
    return $l_Rst; 
}

/// 可能是移动浏览器
function fMayBeMblBrsr()
{
	static $s_MblBrsr = null;
	if (null !== $s_MblBrsr) { return $s_MblBrsr; }
		
	$l_UA = strtolower($_SERVER['HTTP_USER_AGENT']);
	return ($s_MblBrsr = fBool(preg_match('/mobile|phone|android/', $l_UA)));
};

/// 获取通信协议
/// 返回：'http'或'https'
function fGetCommSchm()
{
	// return $_SERVER["REQUEST_SCHEME"]; //【警告】不要使用，未文档化
	return (isset($_SERVER['HTTPS']) && ('on' === $_SERVER['HTTPS'])) ? 'https' : 'http';
}

/// 获取主机名
function fGetHostName()
{
	return $_SERVER['SERVER_NAME'];
}

/// 获取主机端口
function fGetHostPort()
{
	return $_SERVER['SERVER_PORT'];
}

/// 获取请求方法
function fGetRqstMthd()
{
	return $_SERVER["REQUEST_METHOD"];
}

/// 获取Web根目录
/// 返回：String，结尾是“/”
function fGetWebRootDiry()
{
	return stStrUtil::cEnsrDiry($_SERVER['DOCUMENT_ROOT']);
}

/// Web根URL，默认当开发模式是“/wseapp/.pub/”，发布模式是“/”
$g_WebRootUrl = \hpnWse\fIsDvlpMode() ? '/wseapp/.pub/' : '/';

/// 获取Web根URL
function fGetWebRootUrl()
{
	global $g_WebRootUrl;
	return $g_WebRootUrl;
}

/// 设置Web根URL，
function fSetWebRootUrl($a_Url)
{
	global $g_WebRootUrl;
	$g_WebRootUrl = $a_Url;
}

/// 获取WSE目录，即nWse、cnWse、mnWse、slnWse、hpnWse……所在目录
/// 返回：String，以“/”结尾
function fGetWseDiry()
{
	static $s_Rst = null;
	if (null === $s_Rst)
	{ $s_Rst = str_replace('\\', '/', dirname(__DIR__)) . '/'; }
	return $s_Rst;
}

/// 获取部署目录，即WSE目录的父目录
function fGetDploDiry()
{
	static $s_Rst = null;
	if (null === $s_Rst)
	{
		$l_WseDiry = fGetWseDiry();
		$l_Len = stStrUtil::cGetLen($l_WseDiry);
		$s_Rst = dirname(stStrUtil::cSub($l_WseDiry, 0, $l_Len - 1)) . '/';
	}
	return $s_Rst;
}

// /// 获取当前脚本目录
// /// $a_FileSys：Boolean，true=文件系统表示法，false=Web表示法
// /// 返回：String，目录一定以“/”结尾
// function fGetCrntPhpDiry($a_FileSys = false)
// {
// 	$l_UrlPath = dirname($_SERVER['PHP_SELF']) . '/';
// 	return fBool($a_FileSys) ? (fGetWebRootDiry() . $l_UrlPath) : $l_UrlPath;
// }

/// 获取请求完整URL
function fGetRqstFullUrl()
{
	return fMakeHttpUrl(null, null, $_SERVER['REQUEST_URI']);
}

/// 解析查询字符串
/// 返回：Object
function fPseQryStr($a_QryStr = null, $a_DcdKey = false, $a_DcdVal = false)
{
	if (!fBool($a_QryStr)) { $a_QryStr = $_SERVER['QUERY_STRING']; }

	$l_Rst = array();
	$l_Parts = explode('&', $a_QryStr);
	foreach ($l_Parts as $l_Part)
	{
		$l_Kvp = explode("=", $l_Part);
		if (!isset($l_Kvp[1])) { $l_Kvp[1] = ''; }
		if ($a_DcdKey) { $l_Kvp[0] = urldecode($l_Kvp[0]); }
		if ($a_DcdVal && fBool($l_Kvp[1])) { $l_Kvp[1] = urldecode($l_Kvp[1]); }
		$l_Rst[$l_Kvp[0]] = $l_Kvp[1];
	}
	return $l_Rst;
}

/// URL编码查询
/// 返回：String
function fUrlEcdQry($a_Url, $a_Qry)
{
	$l_Rst = fV1OrV2($a_Url, '');
	if (! $a_Qry)
	{ return $l_Rst; }

	$l_KVPs = array();
	foreach ($a_Qry as $l_Pn => $l_Pv)
	{
		if (!fBool($l_Pn) || fIsUdfnOrNull($l_Pv))
		{ continue; }

		$l_KVPs[] = (urlencode($l_Pn) . "=" . urlencode(strval($l_Pv)));
	}

	if (0 == count($l_KVPs))
	{ return $l_Rst; }

	if ($l_Rst)
	{ $l_Rst .= (\hpnWse\stStrUtil::cFind($l_Rst, '?') < 0) ? '?' : '&'; }

	$l_Rst .= implode('&', $l_KVPs);
	return $l_Rst;
}

/// 追加URL查询，即按需使用“?”或“&”拼接
/// a_Url：String，URL，必须有效，若不含“?”则用它拼接，否则用“&”
/// a_Qry：String，查询，必须有效
function fApdUrlQry($a_Url, $a_Qry)
{
	return $a_Url . ((\hpnWse\stStrUtil::cFind($a_Url, '?') < 0) ? '?' : '&') . $a_Qry;
}

/// 制作Http Url
/// $a_Safe：Null$Boolean，安全？true=https，false=http，null=自动判断
/// $a_HostName：String，主机名，默认fGetHostName()
/// $a_WebPath：String，Web路径，必须以“/”开头
function fMakeHttpUrl($a_Safe = null, $a_HostName = null, $a_WebPath = '/')
{
	if (null === $a_Safe) { $l_Rst = fGetCommSchm();  }
	else { $l_Rst = $a_Safe ? 'https' : 'http'; }
	$l_Rst .= '://';
	$l_Rst .= $a_HostName ? $a_HostName : fGetHostName();
	// $i_HostPort = fGetHostPort();
	// if (('80' !== $i_HostPort) && ('443' !== $i_HostPort))
	// {
	// 	$l_Rst .= ':';
	// 	$l_Rst .= $i_HostPort;
	// }
	$l_Rst .= $a_WebPath;
	return $l_Rst;
}

/// 是开发模式？
function fIsDvlpMode()
{
	static $s_Rst = null;
	if (null !== $s_Rst)
	{ return $s_Rst; }

	$l_HostIp = fGetHostIp();
	$s_Rst = ('127.0.0.1' == $l_HostIp) ||
		(0 === strpos($l_HostIp, '10.')) || 
		(0 === strpos($l_HostIp, '172.16.')) || (0 === strpos($l_HostIp, '172.31.')) || 
		(0 === strpos($l_HostIp, '192.168.'));
	return $s_Rst;
}

/// 是发布模式？
function fIsRlsMode()
{
	return ! fIsDvlpMode();
}

/// 布尔实用
class stBoolUtil
{
	/// 转成字符串
	public static function cToStr($a_B)
	{
		return fBool($a_B) ? 'true' : 'false';
	}
}

/// 数字实用
class stNumUtil
{
	/// 获取位
	/// a_Num：Number，数字
	/// a_Idx：Number，索引，最低位是0
	/// 返回：Boolean，若a_Idx位是1则返回true，否则返回false
	public static function cGetBit($a_Num, $a_Idx)
	{
		return (0 != ($a_Num & (0x01 << $a_Idx)));
	}

	/// 设置位
	/// a_Num：Number，数字
	/// a_Idx：Number，索引，最低位是0
	/// a_Val：Boolean，a_Idx位的值，false=0，true=1
	/// 返回：Number，设置后的数字
	public static function cSetBit($a_Num, $a_Idx, $a_Val)
	{
		return $a_Val ? ($a_Num | (0x01 << $a_Idx)) : ($a_Num & ~(0x01 << $a_Idx));
	}

	/// 翻转位
	/// a_Num：Number，数字
	/// a_Idx：Number，索引，最低位是0
	/// 返回：Number，翻转后的数字
	public static function cFlipBit($a_Num, $a_Idx)
	{
		return ($a_Num ^ (0x01 << $a_Idx));
	}

	/// 截断关于数字
	public static function cClmOnNum($a_Num, $a_Min, $a_Max)
	{
		return ($a_Num < $a_Min) ? $a_Min : min($a_Num, $a_Max);
	}

	/// 截断关于字符串
	///【忽略】a_Rst
	public static function cClmOnStr($a_Rst, $a_Str, $a_Bgn, $a_Amt = null)
	{
		return self::cClmOnLen($a_Rst, mb_strlen($a_Str), $a_Bgn, $a_Amt);
	}

	/// 截断关于数组
	///【忽略】a_Rst：若a_Amt为null或undefined则忽略，否则为Object，
	/// {
	/// c_Bgn：Number，截断后的起始索引
	/// c_Amt：Number，截断后的数量
	/// }
	/// a_Ary：Array，数组，若为空则a_Bgn=-1，a_Udfn$Amt=0
	/// a_Bgn：Number，起始索引
	/// a_Amt：undefined$Number，数量
	/// 返回：若a_Amt为null或undefined则返回截断后的起始索引，否则返回a_Rst
	public static function cClmOnAry($a_Rst, $a_Ary, $a_Bgn, $a_Amt = null)
	{
		return self::cClmOnLen($a_Rst, count($a_Ary), $a_Bgn, $a_Amt);
	}

	/// 截断关于长度
	///【忽略】a_Rst
	public static function cClmOnLen($a_Rst, $a_Len, $a_Bgn, $a_Amt)
	{
		$a_Rst = array('c_Bgn'=>-1, 'c_Amt'=>0);

		if ((0 === $a_Len))
		{
			if (null === $a_Amt)
			{ return -1; }

			$a_Rst['c_Bgn'] = -1;
			$a_Rst['c_Amt'] = 0;
			return $a_Rst;
		}

		if ($a_Bgn < 0)
		{ $a_Bgn = 0; }
		else
		if ($a_Bgn > $a_Len - 1)
		{ $a_Bgn = $a_Len - 1; }

		if (null === $a_Amt)
		{ return $a_Bgn; }

		if ($a_Bgn + $a_Amt > $a_Len)
		{ $a_Amt = $a_Len - $a_Bgn; }

		$a_Rst['c_Bgn'] = $a_Bgn;
		$a_Rst['c_Amt'] = $a_Amt;
		return $a_Rst;
	}

	/// 随机浮点数，左闭右开区间，默认[0, 1)
	public static function cRand($a_Min = 0, $a_Lmt = 1)
	{
		$i_Max = mt_getrandmax();
		return $a_Min + (mt_rand(0, $i_Max - 1) / $i_Max) * ($a_Lmt - $a_Min);
	}

	/// 随机整数，闭区间，[$a_Min, $a_Max]
	public static function cRandInt($a_Min, $a_Max)
	{
		return mt_rand($a_Min, $a_Max);
	}

	/// 随机正负号，返回-1或+1
	public static function cRandSign()
	{
		return (self::cRand() < 0.5) ? -1 : +1;
	}
}

/// 字符串实用
class stStrUtil
{
	/// 空串？
	public static function cIsEstr($a_Any)
	{
		return is_string($a_Any) && ('' === $a_Any);
	}

	/// 获取长度
	public static function cGetLen($a_Str)
	{
		return (null === $a_Str) ? 0 : mb_strlen($a_Str);
	}

	/// 子串
	/// $a_Stop：Number，停止索引（不包含），默认null表字符串长度
	public static function cSub($a_Str, $a_Bgn = 0, $a_Stop = null)
	{
		$l_Len = mb_strlen($a_Str);
		if ((null === $a_Stop) || ($a_Stop > $l_Len)) { $a_Stop = $l_Len; }
		if (($a_Stop <= $a_Bgn) || ($a_Bgn >= $l_Len)) { return ''; }
		if ($a_Bgn < 0) { $a_Bgn = 0; }
		return mb_substr($a_Str, $a_Bgn, $a_Stop - $a_Bgn);
	}

	/// 查找子串
	public static function cFind($a_Str, $a_Sub, $a_Bgn = 0)
	{
		$l_Rst = mb_strpos($a_Str, $a_Sub, $a_Bgn);
		return (false === $l_Rst) ? -1 : $l_Rst;
	}

	/// 反向查找子串
	public static function cRvsFind($a_Str, $a_Sub, $a_Bgn = -1)
	{
		$l_Rst = mb_strrpos($a_Str, $a_Sub, $a_Bgn);
		return (false === $l_Rst) ? -1 : $l_Rst;
	}

	/// 编码Html特殊字符
	public static function cEcdHtmlScha($a_Str)
	{
	// '&' (ampersand) becomes '&amp;'  
	// '"' (double quote) becomes '&quot;' when ENT_NOQUOTES is not set.  
	// "'" (single quote) becomes '&#039;' (or &apos;) only when ENT_QUOTES is set.  
	// '<' (less than) becomes '&lt;'  
	// '>' (greater than) becomes '&gt;' 

		return htmlspecialchars($a_Str, 0, 'UTF-8');
	}

	/// 占位符“{{?}}”
	public static $i_Rgx_Plchd = '/\{\{\s*(.+?)\s*\}\}/';

	/// 替换占位符“{{?}}”
	/// a_CplxObj：复杂对象（也可是纯对象或数组），替换值从这里找，未找到则替换成$a_Miss
	/// a_Miss：String，缺失值，默认null表示原样返回
	public static function cRplcPlchd($a_Str, $a_CplxObj, $a_Miss = null)
	{
		$l_IsAry = is_array($a_CplxObj);
		return preg_replace_callback (self::$i_Rgx_Plchd, 
			function ($a_Mchs) use($a_CplxObj, $l_IsAry, $a_Miss)
			{
				$l_Plchd = $a_Mchs[1];
				$l_DftVal = (null === $a_Miss) ? $a_Mchs[0] : $a_Miss;
				$l_EqIdx = self::cFind($l_Plchd, '=');
				if ($l_EqIdx >= 0)
				{
					$l_Plchd = self::cSub($a_Mchs[1], 0, $l_EqIdx);
					$l_DftVal = self::cSub($a_Mchs[1], $l_EqIdx + 1);
				}
				return stObjUtil::cFchPpty2($a_CplxObj, $l_Plchd, $l_DftVal);
			}, $a_Str);
	}

	/// 绝对路径
	public static function cAbsPath($a_Path)
	{
		return realpath($a_Path);
	}

	/// 安全文件名
	public static function cSafeFlnm($a_Path)
	{
		return basename(realpath($a_Path));
	}

	/// 确保目录，即以“/”结尾
	public static function cEnsrDiry($a_Path)
	{
		$a_Path = str_replace('\\', '/', $a_Path);
		$l_Len = self::cGetLen($a_Path);
		if (0 === $l_Len) { return '/'; }
		return ('/' === $a_Path[$l_Len - 1]) ? $a_Path : ($a_Path . '/');
	}

	/// 获取文件扩展名
	public static function cGetFileExtn($a_Path)
	{
		return pathinfo($a_Path, PATHINFO_EXTENSION);
	}

	/// 随机数字
	public static function cRandNum($a_Len)
	{
		$l_Rst = ''; $i;
		for ($i=0; $i<$a_Len; ++$i)
		{ $l_Rst .= strval(stNumUtil::cRandInt(0, 9)); }
		return $l_Rst;
	}

	/// 配对儿标记
	/// a_TagBgn：String，起始标记
	/// 返回：闭合标记，与a_TagBgn配对
	public static function cPairTag($a_TagBgn)
	{
		$a_TagBgn = trim($a_TagBgn);
		$l_Mchs = null;
		$l_OK = preg_match('/^<(\w+)\s+/', $a_TagBgn, $l_Mchs);
		if (!\hpnWse\fBool($l_OK)) { return null; }
		$l_Rst = '</' . $l_Mchs[1] . '>';
		return $l_Rst;
	}

	/// 解析自然数范围，如
	/// “12-34” -> [12,34]，
	/// “-34” -> [0,34]，
	/// “12-” -> [12, PHP_INT_MAX]
	public static function cPseNintRge($a_Str, $a_Sprt = '-')
	{
		$l_Rst = explode($a_Sprt, $a_Str);

		if (fBool($l_Rst[0])) { $l_Rst[0] = intval($l_Rst[0]); }
		else { $l_Rst[0] = 0; }

		if (isset($l_Rst[1]) && fBool($l_Rst[1])) { $l_Rst[1] = intval($l_Rst[1]); }
		else { $l_Rst[1] = PHP_INT_MAX; }

		return $l_Rst;
	}
}

/// 日期实用
class stDateUtil
{
	/// 现在的日期时间
	public static function cNowDatm()
	{
		return date('Y-m-d H:i:s', time());
	}

	/// 从日期时间提取年月日
	/// $a_Datm: String，形如"2017-04-12 16:09:35"
	public static function cExtrYmd($a_Datm)
	{
		return date('Y-m-d', strtotime($a_Datm));
	}

	/// 两个年月日之差
	/// a_Ymd1, a_Ymd2: String，如"2017-03-21"
	/// 返回：Number，天数
	public static function cDiffDays($a_Ymd1, $a_Ymd2)
	{
		$l_D1 = new \DateTime($a_Ymd1);
		$l_D2 = new \DateTime($a_Ymd2);
		$l_Dta = $l_D2->diff($l_D1);

		//【Windows Server：有个BUG，总是返回6015，近似计算】
		if (6015 != $l_Dta->days)
		{ return $l_Dta->days; }

		$l_Y1 = $l_D1->format('Y');  
		$l_Y2 = $l_D2->format('Y');
		$l_Z1 = $l_D1->format('z');
		$l_Z2 = $l_D2->format('z');
		$l_Dta = intval($l_Y2 * 365.2425 + $l_Z2) - intval($l_Y1 * 365.2425 + $l_Z1);
		return $l_Dta;
	}
}

/// 正则表达式实用
class stRgxUtil
{
	/// 测试
	/// 返回：Boolean
	public static function cTest($a_Rgx, $a_Str)
	{
		// 0或false都认为是false
		return (1 === preg_match($a_Rgx, $a_Str));
	}

	/// 获取全部匹配并带有捕获
	public static function cGetAllMchWithCptr($a_Rgx, $a_Str)
	{
		$l_Mch = null;
		$l_Rst = preg_match_all($a_Rgx, $a_Str, $l_Mch, PREG_SET_ORDER);
		return (false === $l_Rst) ? null : $l_Mch;
	}
}

/// 数组实用
class stAryUtil
{
	/// 新建
	public static function cNew($a_Amt = 0, $a_Val = null)
	{
		$l_Rst = array();
		for ($i=0; $i<$a_Amt; ++$i)
		{ $l_Rst[] = $a_Val; }
		return $l_Rst;
	}

	/// 如果是一个元素，新建数组，若本身是数组则原样返回
	/// $a_Fast：参见fIsAry
	public static function cNewIfOne($a_Elmt, $a_Fast = false)
	{
		return \hpnWse\fIsAry($a_Elmt, $a_Fast) ? $a_Elmt : array($a_Elmt);
	}

	/// 转成字符串
	public static function cToStr(&$a_Ary, $a_Sprt = ',')
	{
		return implode($a_Sprt, $a_Ary);
	}

	/// 获取数量
	public static function cGetAmt(&$a_Ary)
	{
		return is_array($a_Ary) ? count($a_Ary) : 0;
	}

	/// 为空？
	public static function cIsEmt(&$a_Ary)
	{
		return 0 == self::cGetAmt($a_Ary);
	}

	/// 索引有效？
	public static function cIsIdxVld(&$a_Ary, $a_Idx)
	{
		return (0 <= $a_Idx) && ($a_Idx < self::cGetAmt($a_Ary));
	}

	/// 遍历，【注意：故意接收$a_Ary副本而非引用，以防遍历期间数组发生变动！】
	/// $a_fCabk：Function，Boolean f(数组, 索引, 元素)
	public static function cFor(&$a_Ary, $a_fCabk)
	{
		$l_Len = self::cGetAmt($a_Ary);
		for ($i=0; $i<$l_Len; ++$i)
		{ $a_fCabk($a_Ary, $i, $a_Ary[$i]); }
	}

	/// 反向遍历，【注意：故意接收$a_Ary副本而非引用，以防遍历期间数组发生变动！】
	/// $a_fCabk：Function，Boolean f(数组, 索引, 元素)
	public static function cRvsFor(&$a_Ary, $a_fCabk)
	{
		$l_Len = self::cGetAmt($a_Ary);
		for ($i=$l_Len-1; $i>=0; --$i)
		{ $a_fCabk($a_Ary, $i, $a_Ary[$i]); }
	}

	/// 查找
	/// $a_fCabk：Function，Boolean f(数组, 索引, 元素)
	public static function cFind(&$a_Ary, $a_fCabk)
	{
		$l_Len = self::cGetAmt($a_Ary);
		for ($i=0; $i<$l_Len; ++$i)
		{
			if ($a_fCabk($a_Ary, $i, $a_Ary[$i]))
			{ return $i; }
		}
		return -1;
	}

	/// 反向查找
	/// $a_fCabk：Function，Boolean f(数组, 索引, 元素)
	public static function cRvsFind(&$a_Ary, $a_fCabk)
	{
		$l_Len = self::cGetAmt($a_Ary);
		for ($i=$l_Len-1; $i>=0; --$i)
		{
			if ($a_fCabk($a_Ary, $i, $a_Ary[$i]))
			{ return $i; }
		}
		return -1;
	}

	/// 通过严格比较查找
	public static function cIdxOf(&$a_Ary, $a_Elmt)
	{
		return self::cFind($a_Ary, function ($a_A, $a_I, $a_E) use($a_Elmt) { return $a_E === $a_Elmt; });
	}

	/// 通过严格比较反向查找
	public static function cLastIdxOf(&$a_Ary, $a_Elmt)
	{
		return self::cRvsFind($a_Ary, function ($a_A, $a_I, $a_E) use($a_Elmt) { return $a_E === $a_Elmt; });
	}

	/// 有指定元素？
	public static function cHasElmt(&$a_Ary, $a_Key)
	{
		return ($a_Ary && $a_Key) ? array_key_exists($a_Key, $a_Ary) : false;
	}

	/// 排序
	/// $a_fCmpr：Function，Number f(值1，值2)，-1=＜，0=＝，+1=＞
	public static function cSort(&$a_Ary, $a_fCmpr)
	{
		$l_Len = self::cGetAmt($a_Ary);
		if ($l_Len < 2)
		{ return $a_Ary; }

		usort($a_Ary, $a_fCmpr);
		return $a_Ary;
	}

	/// 插入
	public static function cIst(&$a_Ary, $a_Idx, $a_Elmt)
	{
		if (self::cGetAmt($a_Ary) <= $a_Idx)
		{
			$a_Ary[] = $a_Elmt;
		}
		else
		{
			array_splice($a_Ary, max(0, $a_Idx), 0, array($a_Elmt)); //【需要套一层数组！】
		}
	}

	/// 擦除
	public static function cErs(&$a_Ary, $a_Idx)
	{
		$a_Idx = stNumUtil::cClmOnAry(null, $a_Ary, $a_Idx);
		if ($a_Idx >= 0)
		{ array_splice($a_Ary, $a_Idx, 1); }
	}

	/// 如果不存在则压入
	public static function cPushIfNonExi(&$a_Ary, $a_Elmt, $a_fCabk = null)
	{
		$l_Idx = $a_fCabk ? self::cFind($a_Ary, $a_fCabk) : self::cIdxOf($a_Ary, $a_Elmt);
		if ($l_Idx < 0)
		{ array_push($a_Ary, $a_Elmt); }
	}

	/// 如果存在则擦除
	public static function cErsIfExi(&$a_Ary, $a_Elmt, $a_fCabk = null)
	{
		$l_Idx = $a_fCabk ? self::cFind($a_Ary, $a_fCabk) : self::cIdxOf($a_Ary, $a_Elmt);
		if ($l_Idx >= 0)
		{ array_splice($a_Ary, $l_Idx, 1); }
	}

	/// 擦除全部
	/// $a_fCabk：Function，Boolean f(数组, 索引, 元素)
	public static function cErsAll(&$a_Ary, $a_fCabk)
	{
		$l_Len = self::cGetAmt($a_Ary);
		for ($i=0; $i<$l_Len; ++$i)
		{
			if ($a_fCabk($a_Ary, $i, $a_Ary[$i]))
			{
				array_splice($a_Ary, $i, 1);
				--$i;
				--$l_Len;
			}
		}
	}

	/// 提取对象属性
	public static function cExtrPpty(&$a_ObjAry, $a_Pn)
	{
		$l_Rst = array();
		$l_Len = count($a_ObjAry);
		for ($i=0; $i<$l_Len; ++$i)
		{ $l_Rst[] = $a_ObjAry[$i][$a_Pn]; }
		return $l_Rst;
	}

	/// 清零
	public static function cZero(&$a_Ary)
	{
		$l_Len = self::cGetAmt($a_Ary);
		if ($l_Len > 0)
		{ array_splice($a_Ary, 0, $l_Len); }
	}

	/// 子数组
	/// $a_Stop：Number，停止索引（不包含），默认null表数组长度
	public static function cSub(&$a_Ary, $a_Bgn = 0, $a_Stop = null)
	{
		if (null === $a_Stop) { $a_Stop = count($a_Ary); }
		return array_slice($a_Ary, $a_Bgn, $a_Stop - $a_Bgn);
	}

	/// 拼接
	public static function cCcat($a_Ary1, $a_Ary2)
	{
		$l_Rst = $a_Ary1;
		return self::cCcatTo($l_Rst, $a_Ary2);
	}

	/// 拼接到
	public static function &cCcatTo(&$a_Ary1, $a_Ary2)
	{
		$l_Len = count($a_Ary2);
		for ($i=0; $i<$l_Len; ++$i)
		{
			$a_Ary1[] = $a_Ary2[$i];
		}
		return $a_Ary1;
	}
}

/// 对象实用
class stObjUtil
{
	/// 获取全类型名，形如"\hpnWse\nMvc\tMdl"
	public static function cGetFullTpnm($a_Obj)
	{
		return self::cEnsrFullTpnm(get_class($a_Obj));
	}

	/// 确保全类型名，即总是以“\”开头
	public static function cEnsrFullTpnm($a_FullTpnm)
	{
		return ('\\' === $a_FullTpnm[0]) ? $a_FullTpnm : ('\\' . $a_FullTpnm);
	}

	/// 获取类型名
	public static function cGetTpnm($a_Obj)
	{
		return self::cExtrTpnm(self::cGetFullTpnm($a_Obj));
	}

	/// 提取类型名，形如"tMdl"
	public static function cExtrTpnm($a_FullTpnm)
	{
		$l_Tpnm = $a_FullTpnm;
		$l_Idx = stStrUtil::cRvsFind($a_FullTpnm, '\\');
		if ($l_Idx >= 0)
		{ $l_Tpnm = stStrUtil::cSub($a_FullTpnm, $l_Idx + 1); }
		return $l_Tpnm;
	}

	/// 读取纯对象属性，若不存在则返回undefined，注意null算存在
	public static function cReadPpty(&$a_PureObj, $a_Pn)
	{
		return array_key_exists($a_Pn, $a_PureObj) ? $a_PureObj[$a_Pn] : \Wse::$i_Udfn;
	}

	/// 获取纯对象属性，若不存在或为null则返回$a_Dft
	public static function cFchPpty(&$a_PureObj, $a_Pn, $a_Dft = null)
	{
		return isset($a_PureObj[$a_Pn]) ? $a_PureObj[$a_Pn] : $a_Dft;
	}

	/// 存取纯对象的对象属性
	/// a_Ctor：String，构造函数，默认array
	public static function cAcsObjPpty(&$a_PureObj, $a_Pn, $a_Ctor = null)
	{
		if (! isset($a_PureObj[$a_Pn]))
		{
			$a_PureObj[$a_Pn] = $a_Ctor ? (new $a_Ctor()) : array();
		}
		return $a_PureObj[$a_Pn];
	}

	/// 纯对象有属性？
	public static function cHasPpty(&$a_PureObj, $a_Pn)
	{
		return is_array($a_PureObj) && array_key_exists($a_Pn, $a_PureObj);
	}

	/// 如果是null就赋值
	/// 返回：如果非null则原样返回，否则返回a_Pv
	public static function cAsnIfNull(&$a_PureObj, $a_Pn, $a_Pv)
	{
		return isset($a_PureObj[$a_Pn]) ? $a_PureObj[$a_Pn] : ($a_PureObj[$a_Pn] = $a_Pv);
	}

	/// 获取复杂对象属性
	/// a_CplxObj：Object，复杂对象（也可是纯对象或数组）
	public static function cFchPpty2($a_CplxObj, $a_Pn, $a_Dft = null)
	{
		if (fIsPureObjOrAry($a_CplxObj))
		{
			if (array_key_exists($a_Pn, $a_CplxObj))
			{ return $a_CplxObj[$a_Pn]; }
		}
		else
		{
			if (property_exists($a_CplxObj, $a_Pn))
			{ return $a_CplxObj->$a_Pn; }
		}
		return $a_Dft;
	}

	/// JSON编码
	/// $a_PureObjOrAry：Object$Array，纯对象或数组
	/// 返回：String
	public static function cEcdJson(&$a_PureObjOrAry)
	{
		// 不要用“\u????”编码汉字
		if (!defined('JSON_UNESCAPED_UNICODE'))
		{
			define('JSON_UNESCAPED_UNICODE', 256);  // Since PHP 5.4.0
		} 
		return strval(json_encode($a_PureObjOrAry, JSON_UNESCAPED_UNICODE));
	}

	/// JSON解码
	/// $a_JsonStr：String，JSON字符串
	/// 返回：Object$Array，纯对象或数组
	public static function cDcdJson($a_JsonStr)
	{
		// 返回Array
		return json_decode($a_JsonStr, true);
	}
}

/// 函数实用
class stFctnUtil
{
	/// 应用
	/// $a_Obj：Object，对象，null表示非实例函数
	/// $a_fCabk：回调函数
	/// $a_Agms：Array，参数数组
	public static function cApl($a_Obj, $a_fCabk, $a_Agms)
	{
		if ($a_Obj && $a_Agms)
		{ return call_user_func_array(array($a_Obj, $a_fCabk), $a_Agms); }
		else
		if ((! $a_Obj) && $a_Agms)
		{ return call_user_func_array($a_fCabk, $a_Agms); }
		else
		if ($a_Obj && (! $a_Agms))
		{ return call_user_func(array($a_Obj, $a_fCabk)); }
		else
		{ return call_user_func($a_fCabk); }
	}
}

/// 模拟JavaScript Array
class tJsAry implements \IteratorAggregate, \ArrayAccess, \Countable
{
	/// Php array
	public $c_PhpAry;

	/// 构造，可接收一个PHP array
	public function __construct($a_PhpAry = null)
	{
		$this->c_PhpAry = $a_PhpAry ? $a_PhpAry : array();
	}

	/// 克隆，【使用默认的就可以】
	// public function __clone()
	// {		
	// }

	/// 获取属性
	public function __get($a_Pn)
	{
		if ('length' === $a_Pn) { return count($this->c_PhpAry); }
	}

	/// 设置属性
	public function __set($a_Pn, $a_Pv)
	{
		if ('length' === $a_Pn)
		{
			// 输入值无效？
			$l_Len = count($this->c_PhpAry);
			if ((! is_int($a_Pv)) || ($a_Pv < 0))
			{ return $l_Len; }

			// 没有变化？
			if ($l_Len === $a_Pv)
			{ return $a_Pv; }

			// 清零？
			if (0 === $a_Pv)
			{
				self::scZero($this);
				return 0;
			}

			// 增加，用undefined填充
			if ($l_Len < $a_Pv)
			{
				for ($i=0; $i<$a_Pv-$l_Len; ++$i)
				{ $this->c_PhpAry[] = \Wse::$i_Udfn; }
			}
			else // 减少，截断
			{
				array_splice($this->c_PhpAry, $a_Pv, $l_Len - $a_Pv);
			}

			return $a_Pv;
		}

		// 其他情况记录在自身之上！
		$this->$a_Pn = $a_Pv;
		return $a_Pv;
	}

	/// 转成字符串
	public function __toString()
	{
		return $this->join();
	}

	/// 实现接口
	public function getIterator()
	{
		return new ArrayIterator($this->c_PhpAry);
	}

	/// 实现接口
	public function offsetSet($a_Ofst, $a_Val)
	{
		// 偏移有效，直接设置
		if (self::scIsIdxVld($this, $a_Ofst))
    	{
    		$this->c_PhpAry[$a_Ofst] = $a_Val;
    	}
    	else // 需要扩容
    	if (count($this->c_PhpAry) <= $a_Ofst)
    	{
    		$this->length = $a_Ofst + 1;
    		$this->c_PhpAry[$a_Ofst] = $a_Val;
    	}
    	else // 其他情况记录在自身之上！
    	{
    		$this->$a_Ofst = $a_Val;
    	}
    	return $a_Val;
    }

    /// 实现接口
    public function offsetExists($a_Ofst)
    {
    	return self::scIsIdxVld($this, $a_Ofst);
	}

	/// 实现接口，【undefined】
    public function offsetUnset($a_Ofst)
    {
    	if (self::scIsIdxVld($this, $a_Ofst))
    	{ $this->c_PhpAry[$a_Ofst] = \Wse::$i_Udfn; }
    }

	/// 实现接口
    public function offsetGet($a_Ofst)
    {
    	return self::scIsIdxVld($this, $a_Ofst) ? $this->c_PhpAry[$a_Ofst] : \Wse::$i_Udfn;
    }

	/// 实现接口
    public function count()
    {
    	return count($this->c_PhpAry);
    }

	//-------- 接口，模拟JS的

    /// 查找元素索引
	public function indexOf($a_Elmt)
	{
		$l_Len = count($this->c_PhpAry);
		for ($i=0; $i<$l_Len; ++$i)
		{
			if ($this->c_PhpAry[$i] === $a_Elmt)
			{ return $i; }
		}
		return -1;
	}

	/// 反向查找元素索引
	public function lastIndexOf($a_Elmt)
	{
		$l_Len = count($this->c_PhpAry);
		for ($i=$l_Len-1; $i>=0; --$i)
		{
			if ($this->c_PhpAry[$i] === $a_Elmt)
			{ return $i; }
		}
		return -1;
	}

	/// 反转
	public function reverse()
	{
		array_reverse ($this->c_PhpAry);
	}

	/// 向头压入，就地
	public function unshift($a___ = null)
	{
		$l_Agms = func_get_args(); $l_AgmAmt = func_num_args();
		$l_Len = count($this->c_PhpAry);
		if (0 === $l_Len)
		{
			for ($i=0; $i<$l_AgmAmt; ++$i)
			{ array_push($this->c_PhpAry, $l_Agms[$i]); }
		}
		else
		{
			for ($i=0; $i<$l_AgmAmt; ++$i)
			{ array_unshift($this->c_PhpAry, $l_Agms[$i]); }
		}
	}

	/// 从头弹出，就地
	public function shift()
	{
		$l_Len = count($this->c_PhpAry);
		if (0 === $l_Len) { return \Wse::$i_Udfn; }
		else { return array_shift($this->c_PhpAry); }
	}

	/// 压入，就地
	public function push($a___ = null)
	{
		$l_Agms = func_get_args(); $l_AgmAmt = func_num_args();
		for ($i=0; $i<$l_AgmAmt; ++$i)
		{ array_push($this->c_PhpAry, $l_Agms[$i]); }
	}

	/// 弹出，就地
	/// 返回弹出的元素，若为空则返回undefined
	public function pop()
	{
		$l_Len = count($this->c_PhpAry);
		if (0 === $l_Len) { return \Wse::$i_Udfn; }
		else { return array_pop($this->c_PhpAry); }
	}

    /// 交接，就地
	/// 返回被删除的元素构成的tJsAry，没有时返回null
	public function splice($a_Bgn = 0, $a_RmvAmt = 0, $a___ = null)
	{
		$l_Agms = func_get_args(); $l_AgmAmt = func_num_args();
		if ($l_AgmAmt < 2)
		{
			return null;
		}
		else // >= 2
		{
			$a_Bgn = $l_Agms[0]; $a_RmvAmt = $l_Agms[1]; 
			array_shift($l_Agms); array_shift($l_Agms); $l_AgmAmt -= 2;
		}

		$l_Len = count($this->c_PhpAry);
		if (0 === $l_Len)
		{
			for ($i=0; $i<$l_AgmAmt; ++$i)
			{ array_push($this->c_PhpAry, $l_Agms[$i]); }
			return null;
		}

		if ($a_Bgn < 0) { $a_Bgn = 0; }
		if ($a_Bgn + $a_RmvAmt > $l_Len) { $a_RmvAmt = $l_Len - $a_Bgn; }
		$l_RmvdPhpAry = array_splice($this->c_PhpAry, $a_Bgn, $a_RmvAmt, $l_Agms);
		return ($a_RmvAmt > 0) ? new self($l_RmvdPhpAry) : null;
	}

	/// 切片，副本
	public function slice($a_Bgn = 0, $a_Stop = null)
	{
		$l_Rst = new self();
		$l_Len = count($this->c_PhpAry);
		if (0 === $l_Len) { return $l_Rst; }

		if ($a_Bgn < 0) { $a_Bgn = 0; }
		if ((null === $a_Stop) || ($a_Stop < 0) || ($l_Len < $a_Stop)) { $a_Stop = $l_Len; }
		if ($a_Bgn >= $a_Stop) { return $l_Rst; }

		for ($i=$a_Bgn; $i<$a_Stop; ++$i)
		{ array_push($l_Rst->c_PhpAry, $this[$i]); }
		return $l_Rst;
	}

	/// 键JS数组
	public function keys()
	{
		return new self(array_keys($this->c_PhpAry));
	}

	/// 连结
	public function join($a_Sprt = ',')
	{
		return implode($a_Sprt, $this->c_PhpAry);
	}

    //-------- 静态函数

    /// 索引存在
    public static function scIsIdxVld($a_JsAry, $a_Idx)
    {
    	return stAryUtil::cIsIdxVld($a_JsAry->c_PhpAry, $a_Idx);
    }

    /// 清零
    public static function scZero($a_JsAry)
    {
    	stAryUtil::cZero($a_JsAry->c_PhpAry); 
    }
}

} // namespace hpnWse


//////////////////////////////////// OVER ////////////////////////////////////